#include "Game.hh"
#include <iostream>
#include <limits>
#include <cstdlib>

Game::Game(const std::string& playerName) {
    player = new Player(playerName);
    gameOver = false;
    playerWon = false;

    initializeRooms();
}

Game::~Game() {
    delete player;

    for (auto room : rooms) {
        delete room;
    }
    rooms.clear();
}

void Game::initializeRooms() {

    // Create a room
    Room* entranceHall = new Room("Entrance Hall", "a spacious hall with old paintings on the walls and several passages to be seen");
    Room* eastCorridor = new Room("East Corridor", "a bright corridor with beautiful tapestries on the walls");
    Room* westCorridor = new Room("West Corridor", "A dimly lit hallway with a musty smell in the air");
    Room* treasureRoom = new Room("The Treasure Room", "a room full of gold and silver treasures, with an ornate treasure chest in the center");
    Room* libraryRoom = new Room("Library", "The dusty shelves are neatly arranged and smell of ink");
    Room* wizardChamber = new Room("The Wizard's Room", "a room full of magic with a glowing magic array in the center");
    Room* healingRoom = new Room("Healing Room", "A room full of healing energy", Room::RoomType::HEALING);
    Room* damageRoom = new Room("Gas chambers", "dangerous rooms filled with toxic gases", Room::RoomType::DAMAGE);

    // New room connection
    entranceHall->addExit("east", eastCorridor);
    entranceHall->addExit("west", westCorridor);
    entranceHall->addExit("above", healingRoom);  // The healing room is upstairs
    entranceHall->addExit("under", damageRoom);   // The gas chambers are underground

    eastCorridor->addExit("west", entranceHall);
    eastCorridor->addExit("north", treasureRoom);
    eastCorridor->addExit("east", libraryRoom);  // Add a connection

    westCorridor->addExit("east", entranceHall);
    westCorridor->addExit("north", damageRoom);   // The gas chambers are also accessible from the West Corridor

    treasureRoom->addExit("south", eastCorridor);
    treasureRoom->addExit("east", libraryRoom);  // The treasure room has direct access to the library

    libraryRoom->addExit("west", treasureRoom);
    libraryRoom->addExit("south", westCorridor);  // Two-way connection
    libraryRoom->addExit("east", wizardChamber);
    libraryRoom->addExit("under", damageRoom);    // The library has secret passages

    wizardChamber->addExit("west", libraryRoom);

    healingRoom->addExit("under", entranceHall);  // The healing room can only return to the entrance

    damageRoom->addExit("above", entranceHall);
    damageRoom->addExit("south", westCorridor);
    damageRoom->addExit("above", libraryRoom);     // Multiple exits increase the chances of escape


    // Add items
    entranceHall->addItem(new Item("Leather Armor", "A simple piece of leather armor that provides basic protection.", 0, 0, 2));
    eastCorridor->addItem(new Item("A Rusty Short Sword", "A rusty but still sharp short sword.", 0, 3, 0));
    treasureRoom->addItem(new Item("Life Potion", "A red potion that restores vitality.", 10, 0, 0));
    treasureRoom->addItem(new Item("Gold Amulet", "A glittering amulet that strengthens the wearer.", 5, 2, 1));
    libraryRoom->addItem(new Item("Magic Scroll", "An ancient scroll on which the knowledge of magic is recorded.", 0, 4, 0));

    // Add enemies
    eastCorridor->addEnemy(new Goblin());
    westCorridor->addEnemy(new Skeleton());
    libraryRoom->addEnemy(new Skeleton());
    wizardChamber->addEnemy(new Wizard());
    eastCorridor->addEnemy(new Troll());  // Add trolls
    westCorridor->addEnemy(new Ghost());   // Add ghosts
    treasureRoom->addEnemy(new Dragon());  // Add dragons
    wizardChamber->addEnemy(new DarkKnight()); // Added the Dark Knight

    // Save all rooms and set the starting room
    rooms.push_back(entranceHall);
    rooms.push_back(eastCorridor);
    rooms.push_back(westCorridor);
    rooms.push_back(treasureRoom);
    rooms.push_back(libraryRoom);
    rooms.push_back(wizardChamber);

    currentRoom = entranceHall;
}

void Game::clearScreen() const {
    // Use system on Windows("cls"), system("clear") on Unix/Linux
#ifdef _WIN32
    system("cls");
#else
    system("clear");
#endif
}

void Game::showMenu() const {
    std::cout << player->toString() << std::endl << std::endl;

    int choice = 1;
    std::map<int, std::string> options;

    // Displays the movement options
    for (const auto& exit : currentRoom->getExits()) {
        options[choice++] = "Move to" + exit.first;
    }

    // Displays item pickup options
    const auto& items = currentRoom->getItems();
    for (size_t i = 0; i < items.size(); ++i) {
        options[choice++] = "pick up" + items[i]->name;
    }

    // Attack options are displayed
    const auto& enemies = currentRoom->getEnemies();
    for (size_t i = 0; i < enemies.size(); ++i) {
        options[choice++] = "attack" + enemies[i]->getName();
    }

    // Show additional options
    options[choice++] = "Check out the backpack";
    options[choice++] = "Check the status";

    // Print the menu
    std::cout << "What do you want to do?" << std::endl;
    for (const auto& option : options) {
        std::cout << option.first << ". " << option.second << std::endl;
    }

    std::cout << "Please enter your selection (1-" << options.size() << "): ";
}

void Game::processCommand(int choice) {
    int currentChoice = 1;

    // Handle move commands
    for (const auto& exit : currentRoom->getExits()) {
        if (choice == currentChoice++) {
            move(exit.first);
            return;
        }
    }

    // Process pickup commands
    const auto& items = currentRoom->getItems();
    for (size_t i = 0; i < items.size(); ++i) {
        if (choice == currentChoice++) {
            takeItem(i);
            return;
        }
    }

    // Handle attack commands
    const auto& enemies = currentRoom->getEnemies();
    for (size_t i = 0; i < enemies.size(); ++i) {
        if (choice == currentChoice++) {
            attackEnemy(i);
            return;
        }
    }

    // Handle other commands
    if (choice == currentChoice++) {
        viewInventory();
    }
    else if (choice == currentChoice++) {
        viewStats();
    }
    else {
        std::cout << "Invalid selection, please try again." << std::endl;
    }
}

void Game::move(const std::string& direction) {
    Room* nextRoom = currentRoom->getExit(direction);
    if (nextRoom) {
        currentRoom = nextRoom;
        clearScreen();
        currentRoom->display();
    }
    else {
        std::cout << "Can't move in that direction!" << std::endl;
    }
}

void Game::takeItem(int itemIndex) {
    Item* item = currentRoom->removeItem(itemIndex);
    if (item) {
        player->addToInventory(item);
    }
    else {
        std::cout << "Unable to pick up this item!" << std::endl;
    }
}

void Game::attackEnemy(int enemyIndex) {
    auto& enemies = currentRoom->getEnemies();
    if (enemyIndex >= 0 && enemyIndex < enemies.size()) {
        Enemy* enemy = enemies[enemyIndex];

        std::cout << "You attacked" << enemy->getName() << "！" << std::endl;

        // The player attacks the enemy
        bool killed = player->attack(*enemy);
        std::cout << "You're right" << enemy->getName() << "caused"
            << player->getAttack() - enemy->getDefense() << "point damage!" << std::endl;

        if (killed) {
            std::cout << "You beat" << enemy->getName() << "！" << std::endl;

            // Check if the Wizard has been defeated
            if (enemy->getName() == "Evil wizard") {
                std::cout << "Congratulations! You have defeated the evil wizard and liberated this dungeon!" << std::endl;
                gameOver = true;
                playerWon = true;
                return;
            }

            // Remove defeated enemies
            currentRoom->removeEnemy(enemy);
            delete enemy;
        }
        else {
            // The enemy counterattacks
            std::cout << enemy->getName() << "Fight back!" << std::endl;
            bool playerKilled = enemy->attack(*player);

            if (playerKilled) {
                std::cout << "You been" << enemy->getName() << "Defeated! Game over." << std::endl;
                gameOver = true;
                return;
            }
        }
    }
    else {
        std::cout << "Invalid target!" << std::endl;
    }
}

void Game::viewInventory() const {
    player->displayInventory();
}

void Game::viewStats() const {
    std::cout << "Your Status:" << std::endl;
    std::cout << player->toString() << std::endl;
}

bool Game::isGameOver() const {
    return gameOver;
}

bool Game::hasPlayerWon() const {
    return playerWon;
}

void Game::run() {
    clearScreen();
    std::cout << "=== Welcome to the dungeon adventure ===" << std::endl;
    std::cout << "You are a brave adventurer and your mission is to explore this ancient dungeon," << std::endl;
    std::cout << "Find and defeat evil wizards and save the cursed land." << std::endl;
    std::cout << "Good luck!" << std::endl << std::endl;

    // Displays the initial room
    currentRoom->display();

    bool inputError = false; // Enter an error flag

    while (!gameOver) {
        clearScreen();
        currentRoom->display();
        showMenu();

        // Displays an error message (if any)
        if (inputError) {
            std::cout << "\033[31m error: Please enter a valid option!\033[0m" << std::endl;
            inputError = false;
        }

        // Use getline to read the entire line of input
        std::string inputLine;
        std::cout << "Please enter an option: ";  // Clearly prompt for a location
        std::getline(std::cin, inputLine);

        // Convert the input to a number
        int choice = 0;
        try {
            choice = std::stoi(inputLine);
        }
        catch (...) {
            inputError = true;
            continue;
        }

        // Verify the range of options
        if (choice < 1 || choice > 10) {
            inputError = true;
            continue;
        }

        // Handle valid inputs
        clearScreen();
        currentRoom->display();
        processCommand(choice);
    }

    if (playerWon) {
        std::cout << "Congratulations on completing the game! You have successfully defeated the evil wizard!" << std::endl;
    }
    else {
        std::cout << "Game over. You didn't get the job done." << std::endl;
    }
}


//游戏系统：
//代码涵盖地牢生成、玩家交互、战斗系统和游戏流程控制等核心功能
// 1.实现了菜单系统，每次玩家在房间里，他们能看到一个可能的动作列表。玩家通过输入相应的数字来选择一个动作。每个房间包括以下的菜单选项：
//移动选项
//选择项目选项
//攻击选项
//查看库存
//查看玩家统计数据
//2.地牢生成：通过房间连接构建复杂地图，包含特殊房间（治愈/毒气）。
//3.玩家管理：控制角色移动、战斗、拾取物品及状态查看。
//4.战斗系统：回合制战斗，支持敌人特殊技能（吸血、闪避等）。
//5.物品系统：装备增强属性，药水恢复生命。
//6.胜利条件：击败最终Boss（邪恶巫师）。


//// Game System:
// The code covers core functions such as dungeon generation, player interaction, combat system, and game flow control.
// 1. Menu system implemented: Every time players are in a room, they can see a list of possible actions. Players select an action by entering the corresponding number. Each room includes the following menu options:
// Move option
// Select item option
// Attack option
// View inventory
// View player statistics
// 2. Dungeon generation: Complex maps are built through room connections, including special rooms (healing/toxic gas).
// 3. Player management: Controls character movement, combat, item picking up, and status viewing.
// 4. Combat system: Turn-based combat, supporting enemy special skills (vampirism, evasion, etc.).
// 5. Item system: Equipment enhances attributes, potions restore health.
// 6. Victory condition: Defeat the final boss (evil wizard).